package com.lingnan.service.impl;

import com.lingnan.dto.ChatMessageDTO;
import com.lingnan.entity.po.*;
import com.lingnan.entity.vo.ChatMessageVO;
import com.lingnan.exception.MyException;
import com.lingnan.feign.UserFeignClient;
import com.lingnan.mapper.*;
import com.lingnan.redis.RedisUtil;
import com.lingnan.service.ChatMessageService;
import com.lingnan.service.ChatSessionService;
import com.lingnan.service.MessageReadService;
import com.lingnan.websocket.ChatWebSocketHandler;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.hibernate.validator.internal.util.stereotypes.Lazy;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
public class ChatMessageServiceImpl implements ChatMessageService {
    @Autowired
    private ChatMessageMapper messageMapper;
    @Autowired
    private RedisUtil redisUtil;

    @Lazy
    @Resource
    private ChatWebSocketHandler webSocketHandler;

    @Resource
    private ChatSessionService sessionService;
    @Resource
    private MessageReadService messageReadService;
    @Resource
    private UserFeignClient userFeignClient;

    @Value("${message.withdraw.timeout:300}") // 默认5分钟(300秒)
    private int withdrawTimeout;
    @Autowired
    private UserAccountMapper userAccountMapper;

    @Override
    @Transactional
    public void sendMessage(ChatMessageDTO dto, Long senderId, Integer senderType) {
        // 新增会话创建逻辑（如果sessionId为空）
        if (dto.getSessionId() == null) {
            Long sessionId = createSessionForMessage(senderId, senderType, dto.getReceiverId());
            dto.setSessionId(sessionId);
            log.info("自动创建会话: sessionId={} (sender={}, receiver={})",
                    sessionId, senderId, dto.getReceiverId());
        }

        // 1. 创建消息实体
        ChatMessage message = new ChatMessage();
        message.setSessionId(dto.getSessionId());
        message.setSenderId(senderId);
        message.setSenderType(senderType);
        message.setReceiverId(dto.getReceiverId());
        message.setReceiverType(dto.getReceiverType());
        message.setContent(dto.getContent());
        message.setFileUrl(dto.getFileUrl());
        message.setMsgType(dto.getMsgType());
        message.setCreatedAt(new Date());

        // 2. 保存到数据库
        messageMapper.insert(message);
        log.info("消息已保存: messageId={}", message.getId());

        // 3. 将消息ID存入Redis(5分钟内可撤回)
        String redisKey = redisUtil.buildKey("msg", String.valueOf(message.getId()));
        redisUtil.setNx(redisKey, "1", (long) withdrawTimeout, TimeUnit.SECONDS);

        // 4. 生成消息预览内容
        String previewContent = getPreviewContent(dto);
        log.info("previewContent={}", previewContent);
        // 5. 更新会话：增加未读计数并设置最后消息（单次操作）
        sessionService.incrementUnreadCount(
                dto.getSessionId(),
                dto.getReceiverId(),  // 使用接收方ID
                previewContent      // 实际消息内容
        );

        log.info("更新会话信息: sessionId={}, receiverId={}, preview={}",
                dto.getSessionId(), dto.getReceiverId(), previewContent);

        // 6. 通过WebSocket实时推送
        webSocketHandler.sendMessage(dto.getReceiverId(), message);
    }

    // 辅助方法：生成消息预览内容（考虑不同消息类型）
    private String getPreviewContent(ChatMessageDTO dto) {
        if (dto.getMsgType() == 2) return "[图片]";
        if (dto.getMsgType() == 3) return "[文件]";
        if (dto.getContent() == null || dto.getContent().isEmpty()) {
            log.warn("空文本消息: sessionId={}", dto.getSessionId());
            return "[文本]";
        }

        String preview = dto.getContent().length() > 20 ?
                dto.getContent().substring(0, 20) + "..." :
                dto.getContent();

        log.debug("生成消息预览: sessionId={}, preview={}",
                dto.getSessionId(), preview);
        return preview;
    }
    private Long createSessionForMessage(Long senderId, Integer senderType, Long receiverId) {
        if (senderType == 0) { // 求职者发消息给HR
            return sessionService.createSession(senderId, receiverId);
        } else if (senderType == 3) { // HR发消息给求职者
            return sessionService.createSession(receiverId, senderId);
        }
        throw new MyException("不支持的发送者类型: " + senderType);
    }



    @Override
    @Transactional
    public void withdrawMessage(Long messageId, Long operatorId) {
        // 1. 验证消息是否存在
        ChatMessage message = messageMapper.selectById(messageId);
        if (message == null) {
            throw new MyException("消息不存在");
        }

        // 2. 验证操作者是否为发送者
        ChatSession session = sessionService.getSessionById(message.getSessionId());
        if (!session.getSeekerId().equals(operatorId) && !session.getHrId().equals(operatorId)) {
            throw new MyException("非会话成员无权操作");
        }

        // 新增身份验证
        if (!message.getSenderId().equals(operatorId)) {
            throw new MyException("仅消息发送者可撤回");
        }

        // 3. 检查Redis中是否存在(是否在5分钟内)
        String redisKey = redisUtil.buildKey("msg", String.valueOf(messageId));
        if (!redisUtil.exist(redisKey)) {
            throw new MyException("超过撤回时限");
        }

        // 4. 更新数据库撤回状态
        message.setIsWithdrawn(true);
        messageMapper.updateById(message);
        log.info("消息已撤回: messageId={}", messageId);

        // 5. 删除Redis记录
        redisUtil.del(redisKey);

        // 6. 发送撤回通知
        webSocketHandler.sendWithdrawNotice(message);
    }

    @Override
    public int getUnreadCount(Long userId, Integer userType) {
        return messageMapper.countUnreadMessages(userId, userType);
    }

    @Override
    public List<ChatMessage> getRecentMessages(Long sessionId, int limit) {
        return messageMapper.getRecentMessages(sessionId, limit);
    }

    @Override
    public List<ChatMessageVO> getChatHistory(Long sessionId, Long userId, Integer userType) {
        // 1. 先标记消息为已读（防止后续转换异常导致未读状态错误）
        messageReadService.markMessagesAsRead(sessionId, userId, userType);

        // 2. 从数据库获取消息历史记录
        List<ChatMessage> messages = messageMapper.getHistoryMessages(sessionId);

        // 3. 转换PO到VO
        List<ChatMessageVO> voList = new ArrayList<>();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        for (ChatMessage msg : messages) {
            ChatMessageVO vo = new ChatMessageVO();

            // 4. 设置基础消息属性
            vo.setId(msg.getId());  // 设置消息ID
            vo.setSessionId(msg.getSessionId());
            vo.setReceiverId(msg.getReceiverId());
            vo.setSenderId(msg.getSenderId());
            vo.setReceiverType(msg.getReceiverType());
            vo.setSenderType(msg.getSenderType());
            vo.setContent(msg.getIsWithdrawn() ? "[该消息已被撤回]" : msg.getContent());
            vo.setFileUrl(msg.getFileUrl());
            vo.setMsgType(msg.getMsgType());
            vo.setIsRead(msg.getIsRead());
            vo.setCreatedAt(sdf.format(msg.getCreatedAt()));

            // 5. 获取发送者信息
            UserAccount sender = getMessageSender(msg);
            if (sender != null) {
                vo.setSenderName(
                        Optional.ofNullable(sender.getNickName())
                                .orElse(sender.getUsername())  // 昵称不存在时使用用户名
                );
                vo.setAvatarUrl(sender.getAvatar());
            } else {
                // 发送者信息缺失时的默认值
                vo.setSenderName("未知用户");
                vo.setAvatarUrl("");
            }

            voList.add(vo);
        }

        return voList;
    }

    // 辅助方法：获取消息发送者的完整信息
    private UserAccount getMessageSender(ChatMessage msg) {
        try {
            if (msg.getSenderType() == 0) { // 求职者
                JobSeeker seeker = userFeignClient.getJobSeekerByUserId(msg.getSenderId()).getData();
                if (seeker != null) {
                    // 通过求职者ID获取关联的用户账户
                    return userFeignClient.getUserAccountById(seeker.getUserId());
                }
            } else if (msg.getSenderType() == 3) { // HR
                CompanyHr hr = userFeignClient.getHrByUserId(msg.getSenderId());
                if (hr != null) {
                    // 直接获取HR关联的用户账户ID
                    return userFeignClient.getUserAccountById(hr.getUserAccountId());
                }
            }
        } catch (Exception e) {
            log.error("获取发送者信息失败: messageId={}, senderType={}",
                    msg.getId(), msg.getSenderType(), e);

            // 提供默认值避免空指针
            return createDefaultAccount(msg.getSenderId());
        }
        return null;
    }

    private UserAccount createDefaultAccount(Long userId) {
        UserAccount account = new UserAccount();
        account.setId(userId);
        account.setUsername("用户" + userId);
        return account;
    }
}
